import json
import random
import os

from metagpt.actions import Action
from metagpt.config2 import Config
from metagpt.logs import logger

from calc_24_points import calc_all_expressions

used_lm_family = None
main_lm = None
math_lm = None

qwen = Config.from_home("qwen2.5.yaml")
qwen_math = Config.from_home("qwen2.5-math.yaml")

deepseek_v3 = Config.from_home("deepseek-v3.yaml")
deepseek_r1 = Config.from_home("deepseek-r1.yaml")

recent_point_list = None


def set_lm_config(lm_family: str = "qwen"):
    global used_lm_family, main_lm, math_lm

    used_lm_family = lm_family
    if lm_family == "deepseek":
        main_lm = deepseek_v3
        math_lm = deepseek_r1
    else:
        main_lm = qwen
        math_lm = qwen_math


def get_used_lm_family():
    global used_lm_family
    return used_lm_family


def get_main_lm():
    global main_lm
    return main_lm


def get_math_lm():
    global math_lm
    return math_lm


# helper functions here

cached_expressions = {}

def get_cached_expressions(point_list: list):
    global cached_expressions
    
    point_list.sort()
    key = json.dumps(point_list)
    
    if key in cached_expressions:
        return cached_expressions[key]
    
    expressions = calc_all_expressions(point_list)
    cached_expressions[key] = expressions
    return expressions


def get_random_suit() -> list:
    suit_list = ['Clubs', 'Hearts', 'Spades', 'Diamonds']
    random.shuffle(suit_list)
    return suit_list


def get_rank_str(point):
    if point == 1:
        rank = "A"
    elif point == 11:
        rank = "J"
    elif point == 12:
        rank = "Q"
    elif point == 13:
        rank = "K"
    else:
        rank = str(point)
    return rank


def get_recent_point_list(context):
    global recent_point_list
    
    card_list = None
    for item in context:
        if item.role == "user" and '"point_list":' in item.content:
            card_list = item.content
    if card_list is not None:
        recent_point_list = card_list
    elif recent_point_list is not None:
        card_list = recent_point_list
    else:
        print("Unknown error!!!")
        os._exit(1)
        
    point_list = json.loads(card_list)["point_list"]
    return point_list


def get_random_card_list(number_list):
    suit_list = get_random_suit()
    
    cards_list = []
    for i in range(4):
        
        point = number_list[i]
        rank = get_rank_str(point)
            
        cards_list.append({"suit": suit_list[i], "rank": rank, "point": point})

    return cards_list


# all action class here

class GetHumanReply(Action):
    PROMPT_TEMPLATE: str = """
    Cards the dealer just posted: {content}
    Please give an expression for the four operations that results in 24.
    Type 'help' if you feel it's difficult.
    Type 'deal' if you want the dealer to deal cards again.
    Type 'exit' if you want to exit this game, type 'exit'.
    """
    name: str = "GetHumanReply"

    async def run(self, content: str):
        prompt = self.PROMPT_TEMPLATE.format(content=content)
        human_reply = await self._aask(prompt)
        return human_reply


class HumanGiveExpression(Action):
    name: str = "HumanGiveExpression"

    async def run(self, content: str):
        return content


class MachineGiveExpression(Action):
    name: str = "MachineGiveExpression"

    async def run(self, context: str):
        point_list = json.loads(recent_point_list)["point_list"]
        if len(point_list) == 0:
            return "expression not found"

        expressions = get_cached_expressions(point_list)
        
        result = "expression not found"
        if len(expressions) > 0:
            random_idx = random.randint(0, len(expressions)-1)
            result = expressions[random_idx]
            print(f"result expression: {result}")
        else:
            print("result expression not found")
        
        return result


class CallMathProdigy(Action):
    name: str = "CallMathProdigy"

    async def run(self, content: str):
        return "CallMathProdigy"


class WrongExpression(Action):
    name: str = "WrongExpression"

    async def run(self, context: str):
        return "WrongExpression"


class RequireDealCardsAgain(Action):
    name: str = "RequireDealCardsAgain"

    async def run(self, content: str):
        return "RequireDealCardsAgain"


class ExitGame(Action):
    name: str = "ExitGame"

    async def run(self, content: str):
        return "ExitGame"
